/*
 * port_c.c
 *
 *  Created on: Sep 9, 2019
 *      Author: ace
 */
#include "riscv_encoding.h"
#include <tos.h>

#define CLINT_CTRL_ADDR 0x2000000
#define CLINT_MSIP      0x0000
#define CLINT_MTIMECMP  0x4000
#define CLINT_MTIME     0xBFF8

__PORT__ void port_systick_config(uint32_t cycle_per_tick)
{

    // it cost cpu read two times, first mtime_lo and then mtime_hi
    // if mtime_lo == 0xFFFFFFFF and mtime_hi = 0 at first read
    // then mtime_lo == 0 and mtime_hi = 1 at next read
    // the result will be  0x1FFFFFFFF, not 0x100000000
    uint64_t mtime = 0;
    while(1) {
        uint32_t mtime_hi = *(volatile uint32_t *)(CLINT_CTRL_ADDR + CLINT_MTIME + 4);
        uint32_t mtime_lo = *(volatile uint32_t *)(CLINT_CTRL_ADDR + CLINT_MTIME + 0);
        uint32_t mtime_hn = *(volatile uint32_t *)(CLINT_CTRL_ADDR + CLINT_MTIME + 4);
        if(mtime_hi == mtime_hn) {
            mtime += ((uint64_t)mtime_hi << 32) | mtime_lo;
            break;
        }
    }

    // just set mtime to mtimecmp does not accurately reflect the passage of time
    // cause some time cost on the path to deal with the interrupt
    // so, we need to to fix the value with a multiple of cycle_per_tick
    uint64_t tick = mtime / cycle_per_tick;
    uint64_t mtimecmp = (tick + 1) * cycle_per_tick;


    // write to mtimecmp register
    *(volatile uint32_t *)(CLINT_CTRL_ADDR + CLINT_MTIMECMP + 0) = 0xFFFFFFFF;
    *(volatile uint32_t *)(CLINT_CTRL_ADDR + CLINT_MTIMECMP + 4) = 0xFFFFFFFF & (mtimecmp >> 32);
    *(volatile uint32_t *)(CLINT_CTRL_ADDR + CLINT_MTIMECMP + 0) = 0xFFFFFFFF & (mtimecmp >>  0);
}

__PORT__ void port_systick_priority_set(uint32_t prio)
{
    //NVIC_SetPriority(SysTick_IRQn, prio);
}
